package hits;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import pagerank.Page;
import pagerank.PageCollection;
import pagerank.Parser;

public class HitsAlgorithm {
	private ArrayList<Page> G; // set of pages
	private PageCollection pageCollection;
	private static final int k = 1000; // suitable value?

	public static void main(String args[]) {
		long start = System.currentTimeMillis();
		Parser parser = new Parser();
		// Parse pages and their forwardlinks
		ArrayList<Page> pages = new ArrayList<Page>();
		HashMap<String, Page> pagesMap = parser.parse("linkCollection.xml");
		// add backlinks
		Iterator<Entry<String, Page>> it = pagesMap.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, Page> entry = it.next();
			Page currPage = entry.getValue();
			// System.out.println(currPage.id);
			for (String s : currPage.fLinks) {
				if (pagesMap.containsKey(s)) {
					pagesMap.get(s).bLinks.add(currPage.id);
				} else {// this page links to a non-existing site

				}
			}
		}
		pages.addAll(pagesMap.values());

		// Pages are now in both an ArrayList<Page> and a HashMap<String, Page>,
		// enjoy!

		int nbrOfPages = pages.size();
		// double d = 0.85; // damping factor
		System.out.println("Number of links: " + nbrOfPages);
		System.out.println("Number of iterations k to run: " + k);

		// PageCollection pageCollection = new PageCollection (pages, pagesMap);

		HitsAlgorithm hits = new HitsAlgorithm(pages, new PageCollection(pages,
				pagesMap));
		hits.execute();
		hits.print();
	}

	private void execute() {
		long start = System.currentTimeMillis();
		for(Page p : G){
			p.auth = 1;
			p.hub = 1;
		}
		HubsAndAuthorities(G, pageCollection);
		
		long end = System.currentTimeMillis();
		
		System.out.println("Execution time: " + (end - start) + " ms");
	}
	
	private void print(){
		Collections.sort(G, new HubComparator());
		System.out.println();
		System.out.println("Hub order ------------------------------------");
		System.out.println();
		System.out.println("ID \t\t\t\t\tHub value");
		for(Page p : G){
			System.out.println(p.id +  "\t" + p.hub);
		}
				
		Collections.sort(G, new AuthComparator());
		System.out.println();
		System.out.println("Auth order ------------------------------------");
		System.out.println();
		System.out.println("ID \t\t\t\t\tAuth value");
		for(Page p : G){
			System.out.println(p.id +  "\t" + p.auth);
		}
		
	}

	private static void HubsAndAuthorities(ArrayList<Page> G,
			PageCollection pageCollection) {
		for (int i = 1; i <= k; i++) {
			double norm = 0;
			for (Page p : G) {
				p.auth = 0;
				p.incomingNeighbours = pageCollection.findNeighbours(p.bLinks);
				for (Page q : p.incomingNeighbours) {
					p.auth += q.hub;
				}
				norm += Math.sqrt(p.auth);
			}
			norm = Math.sqrt(norm);
			for (Page p : G) {
				p.auth = p.auth / norm;
			}
			norm = 0;
			for (Page p : G) {
				p.hub = 0;
				p.outgoingNeighbors = pageCollection.findNeighbours(p.fLinks);
				for (Page r : p.outgoingNeighbors) {
					p.hub += r.auth;
				}
				norm += Math.sqrt(p.hub);
			}
			norm = Math.sqrt(norm);
			for (Page p : G) {
				p.hub = p.hub / norm;
			}
		}

	}

	public HitsAlgorithm(ArrayList<Page> G, PageCollection pageCollection) {
		this.G = G;
		this.pageCollection = pageCollection;
	}

}
